<?php
/**
 * Created by PhpStorm.
 * User: Jaeger <JaegerCode@gmail.com>
 * Date: 2017/9/30
 * Use PhantomJS to crawl Javascript dynamically rendered pages.
 */

namespace Ling\PhantomJs;


use Ling\PhantomJs\Exception\InvalidExecutableException;
use QL\Contracts\PluginContract;
use QL\QueryList;
use Closure;

class PhantomJs implements PluginContract
{
    protected static ?Client $browser = null;

    /**
     * @param QueryList $queryList
     * @param ...$opt
     * @return void
     */
    public static function install(QueryList $queryList, ...$opt): void
    {
        // PhantomJS bin path
        $phantomJsBin = $opt[0];
        $name = $opt[1] ?? 'browser';
        $queryList->bind($name, function ($request, $debug = false, $commandOpt = []) use ($queryList, $phantomJsBin) {
            return PhantomJs::render($queryList, $phantomJsBin, $request, $debug, $commandOpt);
        });

    }

    /**
     * @param QueryList $queryList
     * @param string $phantomJsBin
     * @param mixed $url
     * @param bool $debug
     * @param array $commandOpt
     * @return QueryList
     * @throws InvalidExecutableException
     */
    public static function render(QueryList $queryList, string $phantomJsBin, mixed $url, bool $debug = false, array $commandOpt = []): QueryList
    {
        $client = self::getBrowser($phantomJsBin, $commandOpt);
        $request = $client->getMessageFactory()->createRequest();
        if ($url instanceof Closure) {
            $request = $url($request);
        } else {
            $request->setMethod('GET');
            $request->setUrl($url);
        }
        $response = $client->getMessageFactory()->createResponse();
        if ($debug) {
            $client->getEngine()->debug(true);
        }
        $client->send($request, $response);
        if ($debug) {
            print_r($client->getLog());
            print_r($response->getConsole());
        }
        $html = '<html>' . $response->getContent() . '</html>';
        $queryList->setHtml($html);
        return $queryList;
    }

    /**
     * @param string $phantomJsBin
     * @param array $commandOpt
     * @return Client|null
     * @throws InvalidExecutableException
     * @throws \Exception
     */
    protected static function getBrowser(string $phantomJsBin, array $commandOpt = []): ?Client
    {
        $defaultOpt = [
            '--load-images' => 'false',
            '--ignore-ssl-errors' => 'true'
        ];
        $commandOpt = array_merge($defaultOpt, $commandOpt);

        if (self::$browser == null) {
            self::$browser = Client::getInstance();
            self::$browser->getEngine()->setPath($phantomJsBin);
        }
        foreach ($commandOpt as $k => $v) {
            $str = sprintf('%s=%s', $k, $v);
            self::$browser->getEngine()->addOption($str);
        }
        return self::$browser;
    }

}